package jvs.vfs.opt.home;

import static android.util.Log.d;
import static android.util.Log.w;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import jvs.vfs.FileSystem;
import jvs.vfs.opt.Intents;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Process;

/**
 * Taken from
 * http://android.git.kernel.org/?p=platform/packages/apps/Launcher.git
 * ;a=blob;f=src/com/android/launcher/LauncherModel.java;h=
 * d69bd136337917fcc0ebd0aeb9832368df212cf8;hb=donut-release
 * 
 * @author qiangli
 * 
 */
final class Loader {
	static final boolean DEBUG = FileSystem.DEBUG;;
	static final String LOG_TAG = "Loader";

	private static Loader instance = new Loader();

	static Drawable folderIcon;

	//
	ArrayList<ItemInfo> shortcutList = null;
	ArrayList<ItemInfo> appList = null;
	ArrayList<ItemInfo> widgetList = null;
	ArrayList<ItemInfo> userFolderList = null;
	ArrayList<ItemInfo> liveFolderList = null;

	static {
		try {
			InputStream is = Loader.class
					.getResourceAsStream("/jvs/vfs/opt/home/user_folder.png");
			folderIcon = new BitmapDrawable(BitmapFactory.decodeStream(is));
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private Loader() {
	}

	public static Loader getInstance() {
		return instance;
	}

	public void load(Context ctx) {
		if (DEBUG) {
			d(LOG_TAG, "  ----> running loader");
		}
		android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);

		final ContentResolver cr = ctx.getContentResolver();
		final PackageManager pm = ctx.getPackageManager();
		final AppWidgetManager am = AppWidgetManager.getInstance(ctx);
		//
		initList();
		//
		final ArrayList<ItemInfo> appItems = appList;
		final ArrayList<ItemInfo> shortcutItems = shortcutList;
		final ArrayList<ItemInfo> ufolders = userFolderList;
		final ArrayList<ItemInfo> lfolders = liveFolderList;
		final ArrayList<ItemInfo> appWidgets = widgetList;
		final String sel = LauncherSettings.Favorites.CONTAINER + " = "
				+ LauncherSettings.Favorites.CONTAINER_DESKTOP;

		final Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
				sel, null, null);
		//

		try {
			final int idIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
			final int intentIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
			final int titleIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
			final int iconTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
			final int iconIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
			final int iconPackageIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
			final int iconResourceIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
			final int itemTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
			final int appWidgetIdIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
			final int uriIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);

			while (c.moveToNext()) {
				try {
					int itemType = c.getInt(itemTypeIndex);
					String id = c.getString(idIndex);

					if (DEBUG) {
						d(LOG_TAG, "id: " + id + " type: " + itemType);
					}
					Intent intent;
					String desc;

					switch (itemType) {
					case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
					case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
						ApplicationInfo ai = null;
						desc = c.getString(intentIndex);
						try {
							intent = Intents.parseUri(desc, 0);
						} catch (java.net.URISyntaxException e) {
							continue;
						}
						if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
							ai = getApplicationInfo(pm, intent, ctx);
						} else {
							ai = getApplicationInfoShortcut(c, ctx,
									iconTypeIndex, iconPackageIndex,
									iconResourceIndex, iconIndex);
						}
						if (ai == null) {
							ai = new ApplicationInfo();
							ai.icon = pm.getDefaultActivityIcon();
						}
						if (ai != null) {
							ai.title = c.getString(titleIndex);
							ai.intent = intent;
							ai.id = id;
							if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
								appItems.add(ai);
							} else {
								shortcutItems.add(ai);
							}
						}
						break;
					case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: {
						UserFolderInfo ufi = new UserFolderInfo();
						ufi.title = c.getString(titleIndex);
						ufi.id = id;
						ufi.icon = folderIcon;
						ufolders.add(ufi);
						break;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: {
						LiveFolderInfo lfi = new LiveFolderInfo();
						desc = c.getString(intentIndex);
						intent = null;
						if (desc != null) {
							try {
								intent = Intents.parseUri(desc, 0);
							} catch (java.net.URISyntaxException e) {
								// Ignore, a live folder might not have a base
								// intent
							}
						}
						lfi.title = c.getString(titleIndex);
						lfi.id = id;
						lfi.uri = Uri.parse(c.getString(uriIndex));
						lfi.intent = intent; // baseIntent
						loadLiveFolderIcon(ctx, c, iconTypeIndex,
								iconPackageIndex, iconResourceIndex, lfi);
						lfolders.add(lfi);
						break;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
						break;
					case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
						int appWidgetId = c.getInt(appWidgetIdIndex);
						AppWidgetInfo wi = new AppWidgetInfo();
						wi.appWidgetId = appWidgetId;
						wi.id = id;
						AppWidgetProviderInfo pi = getAppWidgetInfo(am,
								appWidgetId);
						if (pi != null) {
							wi.iconResource = pi.icon;
							wi.title = pi.label;
						}
						appWidgets.add(wi);
						break;
					}
					default:
					}

				} catch (Exception e) {
					w(LOG_TAG, "Desktop items loading interrupted:", e);
				}
			}
		} finally {
			c.close();
		}
		//
		if (DEBUG) {
			d(LOG_TAG, "  --> done loading");
			d(LOG_TAG, "  ----> app=" + appList.size());
			d(LOG_TAG, "  ----> userfolder items=" + userFolderList.size());
			d(LOG_TAG, "  ----> livefolder items=" + liveFolderList.size());
			d(LOG_TAG, "  ----> widgets=" + widgetList.size());
			d(LOG_TAG, "  ----> shortcut=" + shortcutItems.size());
		}
	}

	private static AppWidgetProviderInfo getAppWidgetInfo(AppWidgetManager am,
			int appWidgetId) {
		AppWidgetProviderInfo pi = am.getAppWidgetInfo(appWidgetId);
		if (DEBUG) {
			d(LOG_TAG, "AppWidgetProviderInfo: " + pi);
		}
		return pi;
	}

	private static String makeId(ComponentName c) {
		String n = c.toString().replaceAll("/", "_");
		return FileSystem.encodePath(n);
	}

	static void loadWidgetList(PackageManager pm, AppWidgetManager am,
			ArrayList<ItemInfo> appWidgets) {
		List<AppWidgetProviderInfo> l = am.getInstalledProviders();
		for (AppWidgetProviderInfo i : l) {
			AppWidgetInfo ai = new AppWidgetInfo();
			ai.id = makeId(i.provider);
			ai.title = i.label;
			String pn = i.provider.getPackageName();
			ai.icon = pm.getDrawable(pn, i.icon, null);
			ai.provider = i.provider;
			appWidgets.add(ai);
		}
		if (DEBUG) {
			d(LOG_TAG, "loadWidgetList : " + appWidgets.size());
		}
	}

	private void initList() {
		if (appList == null) {
			appList = new ArrayList<ItemInfo>();
		} else {
			appList.clear();
		}
		if (shortcutList == null) {
			shortcutList = new ArrayList<ItemInfo>();
		} else {
			shortcutList.clear();
		}
		if (widgetList == null) {
			widgetList = new ArrayList<ItemInfo>();
		} else {
			widgetList.clear();
		}
		if (userFolderList == null) {
			userFolderList = new ArrayList<ItemInfo>();
		} else {
			userFolderList.clear();
		}
		if (liveFolderList == null) {
			liveFolderList = new ArrayList<ItemInfo>();
		} else {
			liveFolderList.clear();
		}
	}

	private static ApplicationInfo getApplicationInfo(PackageManager manager,
			Intent intent, Context ctx) {
		final ResolveInfo ri = manager.resolveActivity(intent, 0);

		if (ri == null) {
			return null;
		}
		final ApplicationInfo info = new ApplicationInfo();
		final ActivityInfo ai = ri.activityInfo;
		info.icon = Utilities.createIconThumbnail(ai.loadIcon(manager), ctx);
		info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
		return info;
	}

	private static ApplicationInfo getApplicationInfoShortcut(Cursor c,
			Context ctx, int iconTypeIndex, int iconPackageIndex,
			int iconResourceIndex, int iconIndex) {

		final ApplicationInfo info = new ApplicationInfo();

		info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;

		int iconType = c.getInt(iconTypeIndex);
		switch (iconType) {
		case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
			String packageName = c.getString(iconPackageIndex);
			String resourceName = c.getString(iconResourceIndex);
			PackageManager packageManager = ctx.getPackageManager();
			try {
				Resources resources = packageManager
						.getResourcesForApplication(packageName);
				final int id = resources
						.getIdentifier(resourceName, null, null);
				info.icon = Utilities.createIconThumbnail(resources
						.getDrawable(id), ctx);
			} catch (Exception e) {
				info.icon = packageManager.getDefaultActivityIcon();
			}
			info.iconResource = new Intent.ShortcutIconResource();
			info.iconResource.packageName = packageName;
			info.iconResource.resourceName = resourceName;
			info.customIcon = false;
			break;
		case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
			byte[] data = c.getBlob(iconIndex);
			try {
				Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
						data.length);
				info.icon = new FastBitmapDrawable(Utilities
						.createBitmapThumbnail(bitmap, ctx));
			} catch (Exception e) {
				packageManager = ctx.getPackageManager();
				info.icon = packageManager.getDefaultActivityIcon();
			}
			info.filtered = true;
			info.customIcon = true;
			break;
		default:
			info.icon = ctx.getPackageManager().getDefaultActivityIcon();
			info.customIcon = false;
			break;
		}
		return info;
	}

	private static void loadLiveFolderIcon(Context ctx, Cursor c,
			int iconTypeIndex, int iconPackageIndex, int iconResourceIndex,
			LiveFolderInfo info) {
		int iconType = c.getInt(iconTypeIndex);
		switch (iconType) {
		case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
			String pn = c.getString(iconPackageIndex);
			String rn = c.getString(iconResourceIndex);
			PackageManager pm = ctx.getPackageManager();
			try {
				Resources res = pm.getResourcesForApplication(pn);
				final int id = res.getIdentifier(rn, null, null);
				info.icon = res.getDrawable(id);
			} catch (Exception e) {
				info.icon = folderIcon;
			}
			info.iconResource = new Intent.ShortcutIconResource();
			info.iconResource.packageName = pn;
			info.iconResource.resourceName = rn;
			break;
		default:
			info.icon = folderIcon;
		}
	}

	void refresh() {
		shortcutList = null;
		appList = null;
		widgetList = null;
		userFolderList = null;
		liveFolderList = null;
	}

	static ItemInfo findItem(Context ctx, String itemId) {
		final PackageManager pm = ctx.getPackageManager();
		final AppWidgetManager am = AppWidgetManager.getInstance(ctx);
		final ContentResolver cr = ctx.getContentResolver();
		final Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
				LauncherSettings.Favorites._ID + " = " + itemId, null, null);
		//
		if (DEBUG) {
			d(LOG_TAG, "findUserFolder  itemId: " + itemId);
		}
		try {
			final int idIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
			final int intentIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
			final int titleIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
			final int iconTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
			final int iconIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
			final int iconPackageIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
			final int iconResourceIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
			final int itemTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
			final int appWidgetIdIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
			final int uriIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);

			if (c.moveToNext()) {
				try {
					int itemType = c.getInt(itemTypeIndex);
					String id = c.getString(idIndex);

					if (DEBUG) {
						d(LOG_TAG, "id: " + id + " type: " + itemType);
					}
					Intent intent;
					String desc;

					switch (itemType) {
					case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
					case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
						ApplicationInfo ai = null;
						desc = c.getString(intentIndex);
						try {
							intent = Intents.parseUri(desc, 0);
						} catch (java.net.URISyntaxException e) {
							break;
						}
						if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
							ai = getApplicationInfo(pm, intent, ctx);
						} else {
							ai = getApplicationInfoShortcut(c, ctx,
									iconTypeIndex, iconPackageIndex,
									iconResourceIndex, iconIndex);
						}
						if (ai == null) {
							ai = new ApplicationInfo();
							ai.icon = pm.getDefaultActivityIcon();
						}
						ai.title = c.getString(titleIndex);
						ai.intent = intent;
						ai.id = id;
						return ai;
					case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: {
						UserFolderInfo ufi = new UserFolderInfo();
						ufi.title = c.getString(titleIndex);
						ufi.id = id;
						ufi.icon = folderIcon;
						return ufi;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: {
						LiveFolderInfo lfi = new LiveFolderInfo();
						desc = c.getString(intentIndex);
						intent = null;
						if (desc != null) {
							try {
								intent = Intents.parseUri(desc, 0);
							} catch (java.net.URISyntaxException e) {
								// Ignore, a live folder might not have a base
								// intent
							}
						}
						lfi.title = c.getString(titleIndex);
						lfi.id = id;
						lfi.uri = Uri.parse(c.getString(uriIndex));
						lfi.intent = intent; // baseIntent
						loadLiveFolderIcon(ctx, c, iconTypeIndex,
								iconPackageIndex, iconResourceIndex, lfi);
						return lfi;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
						break;
					case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
						int appWidgetId = c.getInt(appWidgetIdIndex);
						AppWidgetInfo wi = new AppWidgetInfo();
						wi.appWidgetId = appWidgetId;
						wi.id = id;
						AppWidgetProviderInfo pi = getAppWidgetInfo(am,
								appWidgetId);
						if (pi != null) {
							wi.iconResource = pi.icon;
							wi.title = pi.label;
						}
						return wi;
					}
					default:
					}

				} catch (Exception e) {
					w(LOG_TAG, "Desktop items loading interrupted:", e);
				}
			}
		} finally {
			c.close();
		}
		if (DEBUG) {
			d(LOG_TAG, "not found: " + itemId);
		}
		return null;
	}

	static void loadUserFolder(Context ctx, String itemId,
			ArrayList<ItemInfo> list) {
		final PackageManager pm = ctx.getPackageManager();
		final AppWidgetManager am = AppWidgetManager.getInstance(ctx);
		final ContentResolver cr = ctx.getContentResolver();
		final Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
				LauncherSettings.Favorites.CONTAINER + " = " + itemId, null,
				null);
		//
		if (DEBUG) {
			d(LOG_TAG, "loadUserFolder  itemId: " + itemId);
		}
		try {
			final int idIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
			final int intentIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
			final int titleIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
			final int iconTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
			final int iconIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
			final int iconPackageIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
			final int iconResourceIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
			final int itemTypeIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
			final int appWidgetIdIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
			final int uriIndex = c
					.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);

			while (c.moveToNext()) {
				try {
					int itemType = c.getInt(itemTypeIndex);
					String id = c.getString(idIndex);

					if (DEBUG) {
						d(LOG_TAG, "id: " + id + " type: " + itemType);
					}
					Intent intent;
					String desc;

					switch (itemType) {
					case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
					case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
						ApplicationInfo ai = null;
						desc = c.getString(intentIndex);
						try {
							intent = Intents.parseUri(desc, 0);
						} catch (java.net.URISyntaxException e) {
							continue;
						}
						if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
							ai = getApplicationInfo(pm, intent, ctx);
						} else {
							ai = getApplicationInfoShortcut(c, ctx,
									iconTypeIndex, iconPackageIndex,
									iconResourceIndex, iconIndex);
						}
						if (ai == null) {
							ai = new ApplicationInfo();
							ai.icon = pm.getDefaultActivityIcon();
						}
						ai.title = c.getString(titleIndex);
						ai.intent = intent;
						ai.id = id;
						list.add(ai);
						break;
					case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: {
						UserFolderInfo ufi = new UserFolderInfo();
						ufi.title = c.getString(titleIndex);
						ufi.id = id;
						ufi.icon = folderIcon;
						list.add(ufi);
						break;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: {
						LiveFolderInfo lfi = new LiveFolderInfo();
						desc = c.getString(intentIndex);
						intent = null;
						if (desc != null) {
							try {
								intent = Intents.parseUri(desc, 0);
							} catch (java.net.URISyntaxException e) {
								// Ignore, a live folder might not have a base
								// intent
							}
						}
						lfi.title = c.getString(titleIndex);
						lfi.id = id;
						lfi.uri = Uri.parse(c.getString(uriIndex));
						lfi.intent = intent; // baseIntent
						loadLiveFolderIcon(ctx, c, iconTypeIndex,
								iconPackageIndex, iconResourceIndex, lfi);
						list.add(lfi);
						break;
					}
					case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
						break;
					case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
						int appWidgetId = c.getInt(appWidgetIdIndex);
						AppWidgetInfo wi = new AppWidgetInfo();
						wi.appWidgetId = appWidgetId;
						wi.id = id;
						AppWidgetProviderInfo pi = getAppWidgetInfo(am,
								appWidgetId);
						if (pi != null) {
							wi.iconResource = pi.icon;
							wi.title = pi.label;
						}
						list.add(wi);
						break;
					}
					default:
					}

				} catch (Exception e) {
					w(LOG_TAG, "Desktop items loading interrupted:", e);
				}
			}
		} finally {
			c.close();
		}
		if (DEBUG) {
			d(LOG_TAG, "loadUserFolder: " + list.size());
		}
	}

}
